package com.uinnova.product.eam.web.oauth.mvc;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import com.binary.core.exception.BinaryException;
import com.binary.core.lang.StringUtils;
import com.binary.framework.util.ControllerUtils;
import com.binary.framework.web.RemoteResult;
import com.uinnova.product.devcloud.i18n.client.trans.LanguageGetter;
import com.uinnova.product.eam.config.FilterUtil;
import com.uinnova.product.vmdb.comm.doc.annotation.ModDesc;
import com.uinnova.project.base.diagram.comm.constant.CommonConst;
import com.uinnova.project.base.diagram.comm.dto.CurrentUserInfoDTO;
import com.uinnova.project.base.diagram.util.CommonUtil;
import com.uinnova.project.base.diagram.util.RedisUtil;
import com.uinnova.project.service.eam.IEamSysSvc;
import com.uino.api.client.permission.IRoleApiSvc;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.business.CurrentUserInfo;
import com.uino.dao.permission.ESUserSvc;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @version 1.0
 * @Description 集成数字空间相关登录操作
 * @Author wang
 * @Date 2021-08-30-18:54
 */
@RestController
@Slf4j
@RequestMapping("/login")
public class LoginMethodMVC {

    public static final String taibaiUserProfile = "EA:TAIBAI:USER:";

    @Value("${monet.login.loginMethod}")
    private String loginMethod;

    @Autowired
    private RedisUtil redisUtil;

    @Value("${wiki.oauth.client.id}")
    private String CLIENT_ID;

    @Value("${wiki.oauth.client.secret}")
    private String CLIENT_SECRET;

    @Value("${wiki.oauth.client.user_agent}")
    private String USER_AGENT;

    @Value("${local.oauth.client.id}")
    private String LOCAL_CLIENT_ID;

    @Value("${local.oauth.client.secret}")
    private String LOCAL_CLIENT_SECRET;

    @Value("${local.oauth.client.user_agent}")
    private String LOCAL_USER_AGENT;

    @Value("${wiki.oauth.server.url}")
    private String oauthServerUrl;

    @Value("${wiki.oauth.server.token_callback.url}")
    private String callbackUrl;

    @Value("${taibao.login.url:http://29.4.0.155/pages/workbench.html}")
    private String taibaoServerUrl;

    @Autowired
    private IUserApiSvc userApiSvc;

    @Autowired
    private FilterUtil filterUtil;

    @Value("${uino.user.rolename}")
    private String roleName;

    @Autowired
    private IRoleApiSvc roleApiSvc;

    @Autowired(required = false)
    @Lazy
    private LanguageGetter languageGetter;

    @Value("${http.resource.space}")
    private String urlPath;

    @Autowired
    private ESUserSvc userSvc;

    @Autowired
    private IEamSysSvc iEamSysSvc;

    @RequestMapping("/getLoginMethod")
    @ModDesc(desc = "前端获取登录方式", pDesc = "", rDesc = "true-根据token登录，false-根据cookie登录", rType = RemoteResult.class)
    public RemoteResult getLoginMethod() {
        return new RemoteResult(loginMethod);
    }

    @RequestMapping("/deleteLoginUser")
    @ModDesc(desc = "登出用户", pDesc = "", rDesc = "true-成功，false-失败", rType = RemoteResult.class)
    public void deleteLoginUser(@RequestParam String tk, HttpServletRequest request, HttpServletResponse response) throws IOException {
        if("sso".equals(loginMethod)){
            String referer = request.getHeader(Header.REFERER.getValue());
            boolean isLocal = false;
            if (!StringUtils.isEmpty(referer) && referer.contains("localhost")) {
                isLocal = true;
            }

            // 调用数字空间接口 废弃Token
            Object refreshToken = redisUtil.get(tk);
            Map<String, Object> params = new HashMap<>(16);
            params.put("grant_type", "destroy_token");
            params.put("client_id", isLocal ? LOCAL_CLIENT_ID : CLIENT_ID);
            params.put("client_secret", isLocal ? LOCAL_CLIENT_SECRET : CLIENT_SECRET);
            params.put("refresh_token", refreshToken);
            params.put("access_token", tk);
            HttpRequest httpRequest = HttpRequest.post(this.oauthServerUrl + "/oauth/destroy")
                    .contentType(ContentType.FORM_URLENCODED.getValue())
                    .header(Header.USER_AGENT, isLocal ? LOCAL_USER_AGENT : USER_AGENT)
                    .form(params);
            HttpResponse tokenRes = httpRequest.execute();
            if (!tokenRes.isOk()) {
                log.info("destroyToken-请求失败：{}", tokenRes.body());
                new RemoteResult(false);
            }

            redisUtil.del(tk);
            redisUtil.del("Bearer " + tk);
            //重定向
            String state = RandomUtil.randomString(10);
            log.info("deleteLoginUser-state:{}", state);
            String defaultGoPageUrl = callbackUrl.substring(0, callbackUrl.indexOf("/", 10)) + "/#/workbench";
            redisUtil.set(state, defaultGoPageUrl, CommonConst.LOCAL_TOKEN_EXPIRE_TIME);
            String redirectUrl = this.oauthServerUrl + "/oauth/authorize?" +
                    "response_type=code" +
                    "&client_id=" + (isLocal ? LOCAL_CLIENT_ID : CLIENT_ID) +
                    "&redirect_uri=" + callbackUrl +
                    "&state=" + state;
            response.sendRedirect(redirectUrl);
        }else if("taibao".equals(loginMethod)){
            String redisTicket = taibaiUserProfile + tk;
            redisUtil.del(redisTicket);
            response.sendRedirect(taibaoServerUrl);
        }
    }

    @RequestMapping("/getCurrentUser")
    @ModDesc(desc = "前端获取用户登陆状态", pDesc = "", rDesc = "true-已登录，false-未登录", rType = RemoteResult.class)
    public void getCurrentUser(HttpServletRequest request, HttpServletResponse response) {
        SysUser currentUser = SysUtil.getCurrentUserInfo();
        Long userId = currentUser.getId();
        SysUser user = userSvc.getById(userId);
        String icon = user.getIcon();
        if (icon.startsWith("/")) {
            icon = this.urlPath + icon;
        }
        CurrentUserInfo userInfo = CurrentUserInfo.builder().id(userId).icon(icon)
                .domainId(currentUser.getDomainId()).loginCode(user.getLoginCode()).userCode(user.getLoginCode())
                .userName(user.getUserName()).language(languageGetter.getLanguage().name())
                .lastLoginTime(user.getLastLoginTime()).build();
        CurrentUserInfoDTO infoDTO = new CurrentUserInfoDTO();
        BeanUtils.copyProperties(userInfo, infoDTO);
        if("sso".equals(loginMethod)){
            // 获取mmdId
            Long mmdId = iEamSysSvc.getMmdIdByUserId(userId);
            infoDTO.setMmdId(mmdId);
            try {
                // 获取studio的vip信息
                infoDTO.setVipInfo(CommonUtil.getStudioVip(mmdId));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        ControllerUtils.returnJson(request, response, infoDTO);
    }

    @RequestMapping("/getLoginStatus")
    @ModDesc(desc = "前端获取用户登陆状态", pDesc = "", rDesc = "true-已登录，false-未登录", rType = RemoteResult.class)
    public RemoteResult getLoginStatus() {
        return new RemoteResult(true);
    }

    @RequestMapping("/refreshToken")
    @ModDesc(desc = "刷新token", pDesc = "", rDesc = "true-已登录，false-未登录", rType = RemoteResult.class)
    public RemoteResult refreshToken(HttpServletRequest request) {
        String authorization = request.getHeader(Header.AUTHORIZATION.getValue());
        if (StringUtils.isEmpty(authorization)) {
            return new RemoteResult(false);
        }
        String referer = request.getHeader(Header.REFERER.getValue());
        boolean isLocal = false;
        if (!StringUtils.isEmpty(referer) && referer.contains("localhost")) {
            isLocal = true;
        }
        Object refreshTokenObj = redisUtil.get(authorization.substring("Bearer ".length()));
        if (refreshTokenObj == null) {
            return new RemoteResult(false);
        } else {
            //调用数字空间接口刷新token
            String refreshToken = (String) refreshTokenObj;
            Map<String, Object> params = new HashMap<>(16);
            params.put("grant_type", "refresh_token");
            params.put("client_id", isLocal ? LOCAL_CLIENT_ID : CLIENT_ID);
            params.put("client_secret", isLocal ? LOCAL_CLIENT_SECRET : CLIENT_SECRET);
            params.put("refresh_token", refreshToken);
            HttpRequest httpRequest = HttpRequest.post(this.oauthServerUrl + "/oauth/refresh")
                    .contentType(ContentType.FORM_URLENCODED.getValue())
                    .header(Header.USER_AGENT, isLocal ? LOCAL_USER_AGENT : USER_AGENT)
                    .form(params);
            HttpResponse tokenRes = httpRequest.execute();
            if (!tokenRes.isOk()) {
                log.info("refreshToken-请求失败：{}", tokenRes.body());
                return new RemoteResult(false);
            }
            String tokenResBody = tokenRes.body();
            JSONObject jsonObj = new JSONObject(tokenResBody);
            String newOriginToken = jsonObj.getStr("access_token");
            String newRefreshToken = jsonObj.getStr("refresh_token");
            String newAccessToken = "Bearer " + newOriginToken;

            //获取用户信息
            HttpResponse userInfoRes = HttpRequest
                    .get(this.oauthServerUrl + "/api/user/userinfo")
                    .contentType(ContentType.JSON.getValue())
                    .auth(newAccessToken)
                    .header(Header.USER_AGENT, isLocal ? LOCAL_USER_AGENT : USER_AGENT)
                    .execute();

            //对返回信息进行处理
            if (!userInfoRes.isOk()) {
                log.info("刷新token-获取用户信息失败");
                return new RemoteResult(false);
            } else {
                SysUser currUser = filterUtil.getUserByWikiRes(userInfoRes.body());
                if (currUser == null) {
                    log.info("刷新token-用户校验成功，获取详情失败");
                    throw new BinaryException("用户校验成功，获取详情失败");
                }
                redisUtil.set(newAccessToken, currUser, CommonConst.LOCAL_TOKEN_EXPIRE_TIME);
                redisUtil.set(newOriginToken, newRefreshToken, CommonConst.LOCAL_TOKEN_EXPIRE_TIME);
            }
            return new RemoteResult(newOriginToken);
        }
    }
}
